package io.gitee.guoguoleo.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import io.gitee.guoguoleo.annotation.JokerField;
import io.gitee.guoguoleo.annotation.JokerId;
import io.gitee.guoguoleo.annotation.JokerIgnore;
import io.gitee.guoguoleo.enums.FieldStrategy;
import io.gitee.guoguoleo.enums.IdType;
import io.gitee.guoguoleo.handler.IdHandler;
import io.gitee.guoguoleo.model.FieldInfo;
import io.gitee.guoguoleo.model.FieldList;
import io.gitee.guoguoleo.model.ObjectMeta;
import io.gitee.guoguoleo.model.WhereFieldInfo;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.select.SelectItem;
import net.sf.jsqlparser.statement.update.UpdateSet;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

/**
 * sql渲染工具类
 */
@Slf4j
public class SqlRenderUtil {

    /**
     * 设置要搜索的列或者排除要搜索的列，selectColumnList有数据优先使用
     *
     * @param fieldList 列处理对象
     * @return 要查询的列
     */
    public static List<SelectItem<?>> renderSelectItem(FieldList fieldList,List<String> selectList,List<String> excludeList) {
        List<SelectItem<?>> selectItemList = new CopyOnWriteArrayList<>();

        if (CollUtil.isNotEmpty(selectList)) {
            for (String select : selectList) {
                SelectItem<Column> selectItem = new SelectItem<>(new Column(FieldUtil.toField(select)));
                selectItemList.add(selectItem);
            }
        }else {

            for (FieldInfo fieldInfo : fieldList.getAllFieldInfoList()) {
                if (excludeList.contains(fieldInfo.getSqlFieldName())){
                    continue;
                }
                SelectItem<Column> selectItem = new SelectItem<>(new Column(fieldInfo.getSqlFieldName()));
                selectItemList.add(selectItem);
            }
        }
        return selectItemList;
    }

    /**
     * 设置通用搜索条件，逻辑删除
     *
     * @return 通用where条件
     */
    public static Expression renderCommonWhere(FieldInfo delFieldInfo) {
        //1=1
        Expression where = new EqualsTo(new Column("1"), new LongValue(1));

        //逻辑删除
        if (delFieldInfo != null) {
            Column delColumn = new Column(delFieldInfo.getSqlFieldName());
            EqualsTo equalsTo = new EqualsTo();
            equalsTo.withLeftExpression(delColumn);
            Expression expression = SqlUtil.getNotDelValue(delFieldInfo);
            equalsTo.withRightExpression(expression);

            AndExpression andExpression = new AndExpression();
            andExpression.withLeftExpression(where);
            andExpression.withRightExpression(equalsTo);
            where = andExpression;
        }

        return where;
    }


    /**
     * 渲染普通搜索条件
     *
     * @param where               表达式
     * @param whereExpressionList 表达式集合
     * @return where表达式
     */
    public static Expression renderWhere(Expression where, List<WhereFieldInfo> whereExpressionList) {
        for (WhereFieldInfo whereFieldInfo : whereExpressionList) {
            Expression expression = whereFieldInfo.getExpression();
            if (whereFieldInfo.getAndFlag()) {
                where = new AndExpression(where, expression);
            } else if (whereFieldInfo.getOrFlag()) {
                where = new OrExpression(where, expression);
            }
        }
        return where;
    }


    /**
     * 渲染insert字段
     *
     * @param fieldList 字段列表
     * @param entity    实体类
     * @return 列表达式
     */
    public static <T> ExpressionList<Column> renderInsertColumn(FieldList fieldList, T entity)
            throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {


        Map<String, FieldInfo> insertFillFieldMap = new ConcurrentHashMap<>();
        if (CollUtil.isNotEmpty(fieldList.getInsertFillFieldList())) {
            insertFillFieldMap = fieldList.getInsertFillFieldList().stream()
                    .collect(Collectors.toMap(FieldInfo::getFieldName, fieldInfo -> fieldInfo));
        }

        Map<String, String> map = BeanUtils.describe(entity);
        ExpressionList<Column> columns = new ExpressionList<>();
        for (FieldInfo fieldInfo : fieldList.getAllFieldInfoList()) {


            JokerIgnore jokerIgnore = fieldInfo.getField().getAnnotation(JokerIgnore.class);
            if (jokerIgnore != null) {
                if (!jokerIgnore.ignore() && jokerIgnore.ignoreInsert()) {
                    continue;
                }
            }

            if (!map.containsKey(fieldInfo.getFieldName())) {
                continue;
            }

            String value = map.get(fieldInfo.getFieldName());

            //region 有值优先使用存在值的内容
            if (StringUtils.isNotBlank(value)) {
                Column column = new Column(fieldInfo.getSqlFieldName());
                columns.addExpression(column);
                continue;
            }
            //endregion


            //region id
            if (fieldList.getIdField().getFieldName().equals(fieldInfo.getFieldName())) {
                JokerId jokerId = fieldInfo.getField().getAnnotation(JokerId.class);
                if (jokerId.type().equals(IdType.AUTO)) {//自增id不增加
                    continue;
                }
                Column column = new Column(fieldInfo.getSqlFieldName());
                columns.addExpression(column);
                continue;
            }
            //endregion

            //region 删除字段
            if (fieldList.getDelField() != null && fieldList.getDelField().getFieldName().equals(fieldInfo.getFieldName())) {
                Column column = new Column(fieldInfo.getSqlFieldName());
                columns.addExpression(column);
                continue;
            }
            //endregion

            if (CollUtil.isNotEmpty(insertFillFieldMap) && insertFillFieldMap.containsKey(fieldInfo.getFieldName())) {
                Column column = new Column(fieldInfo.getSqlFieldName());
                columns.addExpression(column);
            }

        }

        return columns;

    }


    /**
     * 渲染insert值
     *
     * @param columns 字段列表
     * @param entity  实体类
     * @return 列表达式
     */
    public static <T> ParenthesedExpressionList<Expression> renderInsertValueList(ExpressionList<Column> columns, FieldList fieldList, T entity, Map<String, ObjectMeta> objectMetaMap)
            throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {

        Map<String, FieldInfo> insertFillFieldMap = new ConcurrentHashMap<>();
        if (CollUtil.isNotEmpty(fieldList.getInsertFillFieldList())) {
            insertFillFieldMap = fieldList.getInsertFillFieldList().stream()
                    .collect(Collectors.toMap(FieldInfo::getFieldName, fieldInfo -> fieldInfo));
        }

        ParenthesedExpressionList<Expression> insertValueList = new ParenthesedExpressionList<>();
        Map<String, String> map = BeanUtils.describe(entity);
        for (Column column : columns) {
            String fileName = StrUtil.toCamelCase(column.getColumnName());

            String value = map.get(fileName);
            if (StringUtils.isNotBlank(value)) {
                if (NumberUtil.isNumber(value)) {
                    insertValueList.addExpression(new LongValue(value));
                } else {
                    insertValueList.addExpression(new StringValue(value));
                }
                continue;
            }
            //region id
            if (fieldList.getIdField().getFieldName().equals(fileName)) {
                JokerId jokerId = fieldList.getIdField().getField().getAnnotation(JokerId.class);
                if (jokerId.type().equals(IdType.ASSIGN_ID)) {
                    insertValueList.addExpression(new StringValue(IdUtil.getSnowflakeNextIdStr()));
                } else if (jokerId.type().equals(IdType.ASSIGN_UUID)) {
                    insertValueList.addExpression(new StringValue(IdUtil.fastSimpleUUID()));
                } else if (jokerId.type().equals(IdType.NONE)) {//自定义id插件
                    try{
                        IdHandler idHandler = SpringUtil.getBean(IdHandler.class);
                        insertValueList.addExpression(new StringValue(idHandler.renderId()));
                    }catch (Exception e){
                        log.error("请先实现id生成插件");
                        throw new RuntimeException("请先实现id生成插件");
                    }
                }

                continue;
            }
            //endregion

            //region 删除字段
            if (fieldList.getDelField() != null && fieldList.getDelField().getFieldName().equals(fileName)) {
                insertValueList.addExpression(SqlUtil.getNotDelValue(fieldList.getDelField()));
                continue;
            }
            //endregion


            if (CollUtil.isNotEmpty(insertFillFieldMap) && insertFillFieldMap.containsKey(fileName)) {
                StringValue fillValue = new StringValue("");
                if (CollUtil.isNotEmpty(objectMetaMap) || objectMetaMap.containsKey(fileName)) {
                    ObjectMeta objectMeta = objectMetaMap.get(fileName);
                    if (objectMeta != null) {
                        fillValue.setValue(objectMeta.getFieldVal().toString());
                    }
                }
                insertValueList.addExpression(fillValue);
            }


        }
        return insertValueList;
    }


    public static void renderCommonSet(List<UpdateSet> updateSets, FieldList fieldList, Map<String, ObjectMeta> objectMetaMap) {

        //没有填充的值直接不处理
        if (CollUtil.isEmpty(fieldList.getUpdateFillFieldList())) {
            return;
        }

        //region 已经存在在set的值
        Map<String, UpdateSet> updateSetMap = new ConcurrentHashMap<>();
        if (CollUtil.isNotEmpty(updateSets)) {
            updateSets.forEach(updateSet -> updateSetMap.put(StrUtil.toCamelCase(updateSet.getColumn(0).getColumnName()), updateSet));
        }
        //endregion

        for (FieldInfo fieldInfo : fieldList.getUpdateFillFieldList()) {
            //该值已经存在，跳过
            if (CollUtil.isNotEmpty(updateSetMap) && updateSetMap.containsKey(fieldInfo.getFieldName())) {
                continue;
            }

            if (CollUtil.isNotEmpty(objectMetaMap) && objectMetaMap.containsKey(fieldInfo.getFieldName())) {
                ObjectMeta objectMeta = objectMetaMap.get(fieldInfo.getFieldName());
                if (objectMeta != null) {
                    UpdateSet updateSet = new UpdateSet();
                    updateSet.add(new Column(fieldInfo.getSqlFieldName()), new StringValue(objectMeta.getFieldVal().toString()));
                    updateSets.add(updateSet);
                }
            }

        }
    }


}
